<?php

/**
 * +--------------------------------------------------------------
 * | eLuoPHP
 * +--------------------------------------------------------------
 * | Copyright (c) 2016-2018 http://qxwoo.cn All rights reserved.
 * +--------------------------------------------------------------
 * | y139w [y139w@163.com]
 * +--------------------------------------------------------------
 * | 数据库查询类文件
 * +--------------------------------------------------------------
 */
namespace luo\db;

use luo\Db;

class Query
{

    /**
     * 数据库连接
     * @var mixed
     */
    private $db;

    /**
     * 主键
     * @var string
     */
    private $pk;

    /**
     * 参数
     * @var array
     */
    private $param = [];

    /**
     * 数据表
     * @var string
     */
    private $table;

    /**
     * Sql对象
     * @var Sql object
     */
    private $sql;

    /**
     * 最后执行的SQL
     * @var string
     */
    private $lastSql = '';

    /**
     * Query constructor.
     * @param Db $db
     * @param Sql $sql
     * @throws \ReflectionException
     */
    public function __construct(Db $db, Sql $sql)
    {
        // 获取数据库连接
        $this->db = $db::connect();
        // 获取Sql类
        $this->sql = $sql;

    }

    /**
     * 查询多条数据
     * @return mixed
     */
    public function select(){

        $sql = $this->sql->getSql('select', $this->parseParam());
        $rows = ($this->db->query($sql, []));
        $this->param = [];
        return $rows;

    }

    /**
     * 查询一条数据
     * @param null $pk
     * @return mixed
     */
    public function find($pk = null){

        if(!empty($pk)){
            $this->where($this->table . '.' . $this->pk, $pk);
        }
        $this->limit(1);
        $sql = $this->sql->getSql('select', $this->parseParam());
        $rows = ($this->db->query($sql, []));
        $this->param = [];
        return isset($rows[0]) ? $rows[0] : null;

    }

    /**
     * 处理字段下划线为驼峰命名方式
     * @param array $rows
     * @return array
     */
    private function fieldToHump(array $rows){

        $data = [];
        foreach($rows as $key=>$val){
            $row = [];
            foreach($val as $k=>$v){
                if(strpos($k, '_')){
                    $kArray = explode('_', $k);
                    $k = implode('', [$kArray[0], ucfirst($kArray[1])]);
                }
                $row[$k] = $v;
            }
            $data[$key] = $row;
        }
        return $data;

    }

    /**
     * 数据条数
     * @return mixed
     */
    public function count(){

        $this->param['cols']  = isset($this->param['field']) ? $this->param['field'] : '';
        if($this->pk){
            $this->param['field'] = "count(`{$this->table}`.`{$this->pk}`) as count";
        }else{
            $this->param['field'] = "count(1) as count";
        }
        $this->param['limit'] = [];
        $sql = $this->sql->getSql('select', $this->parseParam());
        $rows = $this->db->query($sql, []);
        $this->param['field']  = $this->param['cols'];
        //$this->param = [];
        $row = isset($rows[0]) ? $rows[0] : null;
        return $row['count'];

    }


    /**
     * 删除一条记录
     * @param null $pk
     * @return mixed
     */
    public function delete($pk = null){

        $pk = empty($pk) ? false : $pk;
        if($pk){
            $this->where($this->table . '.' . $this->pk, $pk);
        }
        $sql = $this->sql->getSql('delete', $this->parseParam());
        $rows = $this->db->execute($sql, []);
        $this->param = [];
        return $rows;

    }

    /**
     * 更新
     * @param $data
     * @param null $pk
     * @return mixed
     */
    public function update($data, $pk = null){

        foreach($data as $key=>$val){
            if($key == $this->pk){
                unset($data[$key]);
                $pk = $val;
            }
        }

        if(!is_null($pk)){
            $this->where($this->pk, $pk);
        }

        $this->param['data'] = $data;

        $sql = $this->sql->getSql('update', $this->parseParam());
        $result = $this->db->execute($sql, []);
        $this->param = [];
        return $result;

    }

    /**
     * 添加并获取用户id
     * @param $data
     * @return mixed
     */
    public function insert(Array $data){

        $this->param['data'] = $data;
        $sql = $this->sql->getSql('insert', $this->parseParam());
        $rows = $this->db->execute($sql);
        if($rows){
            $id = $this->db->lastInsertId();
            $id = $id ? $id : $rows;
        }else{
            $id = false;
        }
        $this->param=[];
        return $id;
    }

    /**
     * 查询表结构
     * @param string $table
     * @return array
     */
    public function desc($table = ''){

        if(empty($table)){
            $table = $this->table;
        }
        $sql = 'desc `' . $table . '`';
        $desc = $this->db->query($sql);
        $array = [];
        foreach($desc as $key=>$val){
            $array[$key]['field'] = $val['Field'];
            $array[$key]['key'] = $val['Key'];
        }
        return $array;

    }

    /**
     * 获取当前表主键
     * @param string $table
     * @return string
     */
    public function pk($table = ''){

        $pk = '';
        if(empty($table)){
            $table = $this->table;
        }

        foreach($this->desc($table) as $val){
            if($val['key'] == 'PRI'){
                $pk = $val['field'];
                break;
            }
        }
        $this->pk = $pk;

        return $pk;

    }

    /**
     * 设置数据表
     * @param $table
     * @return $this
     */
    public function table($table){

        $this->param['from'] = $table;
        $this->table = $table;
        $this->pk();
        return $this;

    }

    /**
     * 设置返回的字段
     * @param $fields
     * @return $this
     */
    public function field($fields){

        $field = isset($this->param['field']) ? $this->param['field'] : [];
        if(is_bool($fields) && $fields){
            foreach($this->desc() as $key=>$val){
                $field[] = '`' . $this->table . '`.`' . $val['field'] . '`';
            }
        }else{
            $field = $fields;
        }
        $this->param['field'] = $field;
        return $this;

    }

    /**
     * 设置条件
     * @param $field
     * @param null $operation
     * @param null $condition
     * @param string $type
     * @return $this
     */
    public function where($field, $operation = null, $condition = null, $type = 'and'){

        $where = isset($this->param['where']) ? $this->param['where'] : [];

        if(!is_null($operation)){
            if(is_null($condition)){
                $condition = $operation;
                $operation = '=';
            }
            array_push($where, [$field, $operation, $condition, $type]);
        }

        if(is_string($field) && is_null($operation)) {
            $where = $field;
        }
        if(is_array($field) && is_null($operation)){

            if(isset($field[0]) && !is_array($field[0])){
                $field = [$field];
            }
            foreach($field as $key=>$val){

                if(is_numeric($key)){

                    // in条件处理
                    if(strtolower($val[1]) == 'in'){
                        if(is_array($val[2])){
                            $val[2] = '( ' . implode(',', $val[2]) . ' )';
                        }else{
                            $val[2] = '( ' . $val[2] . ' )';
                        }
                    }
                    // null|not null条件处理
                    if(strtolower($val[2]) == 'null' or strtolower($val[2]) == 'not null'){
                        $val[1] = 'is';
                    }
                    // between条件处理
                    if(strtolower($val[1]) == 'between'){
                        if(is_array($val[2])){
                            $val[2] = $val[2][0] . ' and ' . $val[2][1];
                        }
                    }
                    array_push($where, $val);
                }else{
                    array_push($where, [$key, '=', $val, $type]);
                }
            }
        }
        $this->param['where'] = $where;
        return $this;

    }

    /**
     * 设置条件
     * @param $field
     * @param null $operation
     * @param null $condition
     * @return $this
     */
    public function whereOr($field, $operation = null, $condition = null){

        $this->where($field, $operation, $condition, 'or');
        return $this;

    }

    /**
     * 数据排序
     * @param $order
     * @return $this
     */
    public function order($order){

        $this->param['order'] = $order;
        return $this;

    }

    /**
     * 设置返回记录条数
     * @param $limit
     * @return $this
     */
    public function limit($limit){
        $this->param['limit'] = $limit;
        return $this;

    }

    /**
     * @param $table
     * @param null $condition
     * @param string $type
     * @return $this
     */
    public function join($table, $condition = null, $type = 'inner'){

        $join = isset($this->param['join']) ? $this->param['join'] : [];
        if(!is_null($condition)){
            if(is_array($table) && !is_null($condition)){
                foreach($table as $key=>$val){
                    $name = ' `' . $key . '` as ' . $val . ' ';
                    if(is_numeric($key)){
                        $name = ' `' . $val . '` ';
                    }
                    if(is_array($condition)){
                        $term = array_shift($condition);
                    }else{
                        $term = $condition;
                    }
                    array_push($join, [$name, $term, $type]);
                }
            }
            if(is_string($table)){
                array_push($join, [$table, $condition, $type]);
            }
        }else{
            if(is_array($table) && is_null($condition)){
                foreach($table as $key=>$val){
                    array_push($join, $val);
                }
            }
        }
        $this->param['join'] = $join;
        return $this;

    }

    /**
     * 别名
     * @param $as
     * @return $this
     */
    public function alias($as){
        $this->param['as'] =" as ".$as." ";
        return $this;

    }

    /**
     * 自动处理表单提交数据，和数据库中表的字段匹配
     * @param $data
     * @param bool $isPk
     * @return $this
     */
    public function data($data, $isPk = false){

        $array = [];
        foreach($this->desc() as $key=>$val){
            if($this->pk() == $val['field'] && $isPk){
                continue;
            }
            $array[$val['field']] = $data[$val['field']];
        }
        $this->param['data'] = $array;
        return $this;

    }

    /**
     * 最后执行的sql语句
     * @return string
     */
    public function getLastSql(){

        return $this->lastSql = $this->db->getLastSql();

    }

    /**
     * @param $str
     * @return $this
     */
    public function group($str){

        $group = [];
        if(!is_array($str)){
            $group = [$str];
        }
        $this->param['group'] = $group;

        return $this;
    }

    /**
     * group的条件
     * @param $str
     * @return $this
     */
    public function having($str){

        $this->param['having'] = $str;
        return $this;

    }

    /**
     * 解析Sql参数
     * @return array
     */
    protected function parseParam(){

        $param = $this->param;

        if(!isset($param['from'])){
            $param['from'] = $this->table;
        }

        if(!isset($param['where'])){
            $param['where'] = [];
        }

        if(!isset($param['field'])){
            $this->field(true);
            $param['field'] = [];
            if(!empty($this->param['field'])){
                $param['field'] = $this->param['field'];
            }
        }

        if(!isset($param['group'])){
            $param['group'] = [];
        }

        if(!isset($param['having'])){
            $param['having'] = [];
        }

        if(!isset($param['order'])){
            $param['order'] = [];
        }

        if(!isset($param['limit'])){
            $param['limit'] = [];
        }
        if(!isset($param['join'])){
            $param['join'] = "";
        }
        if(!isset($param['as'])){
            $param['as'] = "";
        }
        if(!isset($param['data'])){
            $param['data'] = [];
        }
        return $param;

    }

    /**
     * 开启事务
     * @return mixed
     */
    public function begin(){

        return  $this->db->begin();

    }

    /**
     * 事务回滚
     * @return mixed
     */
    public function rollback(){

        return  $this->db->rollback();

    }

    /**
     * 提交事务
     * @return mixed
     */
    public function commit(){

        return  $this->db->commit();

    }

}